﻿using System.Collections.Generic;
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MugenInjection;
using MugenInjection.Attributes;
using MugenInjection.Core.Components;
using MugenInjection.Infrastructure;
using MugenInjection.Interface;
using Should;

namespace MugenInjectionTest.Converters
{
    [TestClass]
    public class WithSettingsConverterTest : ConverterTestBase<SettingsWrapperConverter>
    {

        [TestMethod]
        public void GetInstanceWithCustomSettingTest()
        {
            const string value = "value";
            using (MugenInjector injector = GetInjector())
            {
                injector.Components.BindingActivatorComponent.RemoveAllConverters();
                var converter = CreateNew();
                injector.Components.BindingActivatorComponent.AddConverter(converter);
                converter.SettingWrapperTypes.Add(typeof(WithCustomSettings<>));

                var dict = new Dictionary<string, object>();
                injector.Bind<string>().ToConstant(value).WithSetting(value, value);

                var withSettings = injector.Get<WithCustomSettings<string>>(dict);
                withSettings.Value.ShouldEqual(value);
                withSettings.Settings[value].ShouldEqual(value);
                withSettings.SpecialParameters.ShouldEqual(dict);
            }
        }

        [TestMethod]
        public void GetInstanceWithSettingTest()
        {
            const string value = "value";
            using (MugenInjector injector = GetInjector())
            {
                injector.Components.BindingActivatorComponent.RemoveAllConverters();
                injector.Components.BindingActivatorComponent.AddConverter(CreateNew());

                var dict = new Dictionary<string, object>();
                injector.Bind<string>().ToConstant(value).WithSetting(value, value);

                var withSettings = injector.Get<WithSettings<string>>(dict);
                withSettings.Value.ShouldEqual(value);
                withSettings.Settings[value].ShouldEqual(value);
                withSettings.SpecialParameters.ShouldEqual(dict);
            }
        }

        [TestMethod]
        public void WithSettingsInConstructorAndPropertyInjectTest()
        {
            const string value = "value";
            using (MugenInjector injector = GetInjector())
            {
                injector.Components.BindingActivatorComponent.RemoveAllConverters();
                var converter = CreateNew();
                injector.Components.BindingActivatorComponent.AddConverter(converter);
                converter.SettingWrapperTypes.Add(typeof(WithCustomSettings<>));

                var dict = new Dictionary<string, object>();
                injector.Bind<WithSettingClass>().ToSelf();
                injector.Bind<string>().ToConstant(value).WithSetting(value, value);

                var settingClass = injector.Get<WithSettingClass>(dict);
                settingClass.WithSettings.SpecialParameters.ShouldEqual(dict);
                settingClass.WithSettingsProp.SpecialParameters.ShouldEqual(dict);
                settingClass.WithCustomSettings.SpecialParameters.ShouldEqual(dict);
                settingClass.WithCustomSettingsProp.SpecialParameters.ShouldEqual(dict);

                settingClass.WithSettings.Settings[value].ShouldEqual(value);
                settingClass.WithSettingsProp.Settings[value].ShouldEqual(value);
                settingClass.WithCustomSettings.Settings[value].ShouldEqual(value);
                settingClass.WithCustomSettingsProp.Settings[value].ShouldEqual(value);
            }
        }

        #region Overrides of ConverterTestBase<WithSettingsConverter>

        protected override SettingsWrapperConverter CreateNew()
        {
            return new SettingsWrapperConverter();
        }

        #endregion

        #region Nested type: WithCustomSettings

        /// <summary>
        ///     Provides a value along with a dictionary of metadata describing the value.
        /// </summary>
        /// <typeparam name="T">The type of the value.</typeparam>
        public class WithCustomSettings<T>
        {
            #region Constructors

            /// <summary>
            ///     Initializes a new instance of the <see cref="WithSettings{T}" /> class.
            /// </summary>
            public WithCustomSettings(T value, IDictionary<string, object> settings, IDictionary<string, object> specialParameters)
            {
                Settings = settings;
                SpecialParameters = specialParameters;
                Value = value;
            }

            #endregion

            #region Properties

            /// <summary>
            ///     Gets the value.
            /// </summary>
            public T Value { get; private set; }

            /// <summary>
            ///     Gets the binding settings.
            /// </summary>
            public IDictionary<string, object> Settings { get; private set; }

            /// <summary>
            ///     Gets the special parameters.
            /// </summary>
            public IDictionary<string, object> SpecialParameters { get; private set; }

            #endregion
        }

        #endregion

        #region Nested type: WithSettingClass

        public class WithSettingClass
        {
            public WithSettings<string> WithSettings { get; set; }

            public WithCustomSettings<string> WithCustomSettings { get; set; }

            [Inject]
            public WithSettings<string> WithSettingsProp { get; set; }

            [Inject]
            public WithCustomSettings<string> WithCustomSettingsProp { get; set; }

            public WithSettingClass(WithSettings<string> withSettings, WithCustomSettings<string> withCustomSettings)
            {
                WithSettings = withSettings;
                WithCustomSettings = withCustomSettings;
            }
        }

        #endregion
    }

    [TestClass]
    public class BindingSettingsConverterTest : ConverterTestBase<BindingSettingsConverter>
    {
        [TestMethod]
        public void SettingsInConstructorAndPropertyInjectTest()
        {
            const string value = "value";
            using (MugenInjector injector = GetInjector())
            {
                injector.Components.BindingActivatorComponent.RemoveAllConverters();
                injector.Components.BindingActivatorComponent.AddConverter(CreateNew());

                injector.Bind<SettingClass>().ToSelf().WithSetting(value, value);
                var settingClass = injector.Get<SettingClass>();
                settingClass.Settings[value].ShouldEqual(value);
                settingClass.PropertySettings[value].ShouldEqual(value);
                settingClass.Settings.ShouldEqual(settingClass.PropertySettings);
            }
        }

        [TestMethod]
        public void SettingDictionaryInConstructorAndPropertyInjectTest()
        {
            const string value = "value";
            using (MugenInjector injector = GetInjector())
            {
                injector.Components.BindingActivatorComponent.RemoveAllConverters();
                injector.Components.BindingActivatorComponent.AddConverter(CreateNew());

                injector.Bind<SettingDictionaryClass>().ToSelf().WithSetting(value, value);
                var settingClass = injector.Get<SettingDictionaryClass>();
                settingClass.Settings[value].ShouldEqual(value);
                settingClass.PropertySettings[value].ShouldEqual(value);
                settingClass.Settings.ShouldEqual(settingClass.PropertySettings);
            }
        }

        [TestMethod]
        public void SettingDictionaryExplicitInConstructorAndPropertyInjectTest()
        {
            const string value = "value";
            using (MugenInjector injector = GetInjector())
            {
                var dict = new Dictionary<string, object>();
                injector.Components.BindingActivatorComponent.RemoveAllConverters();
                injector.Components.BindingActivatorComponent.AddConverter(CreateNew());

                injector.Bind<SettingDictionaryClass>().ToSelf().WithSetting(value, value);
                injector.Bind<IDictionary<string, object>>().ToConstant(dict);

                var settingClass = injector.Get<SettingDictionaryClass>();
                settingClass.Settings.ShouldEqual(dict);
                settingClass.PropertySettings.ShouldEqual(dict);
            }
        }

        #region Overrides of ConverterTestBase<BindingSettingsConverter>

        protected override BindingSettingsConverter CreateNew()
        {
            return new BindingSettingsConverter();
        }

        #endregion

        #region Nested type: SettingClass

        public class SettingClass
        {
            public ISettings Settings { get; set; }

            [Inject]
            public ISettings PropertySettings { get; set; }

            public SettingClass(ISettings settings)
            {
                Settings = settings;
            }
        }

        #endregion

        #region Nested type: SettingDictionaryClass

        public class SettingDictionaryClass
        {
            public IDictionary<string, object> Settings { get; set; }

            [Inject]
            public IDictionary<string, object> PropertySettings { get; set; }

            public SettingDictionaryClass(IDictionary<string, object> settings)
            {
                Settings = settings;
            }
        }

        #endregion
    }
}
